﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using OpenGL;

using OpenCvSharp;

namespace HTEffectSharp
{
    class Program
    {
        // === 引用HTEffectSDK C++动态库和方法 start ===
        // 如果是Debug模式，HTEffect.dll需改为HTEffectD.dll
#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "authorizeSDK")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "authorizeSDK")]
#endif
        public static extern int authorizeSDK(String license, String resDir);

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "initBufferRenderer")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "initBufferRenderer")]
#endif
        public static extern bool initBufferRenderer(int format, int width, int height, int rotation, bool isMirror, int maxFaces);

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "processBuffer")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "processBuffer")]
#endif

        public static extern void processBuffer(IntPtr buffer);

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "releaseBufferRenderer")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "releaseBufferRenderer")]
#endif
        public static extern void releaseBufferRenderer();

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "initImageRenderer")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "initImageRenderer")]
#endif
        public static extern bool initImageRenderer(int format, int width, int height, int rotation, bool isMirror, int maxFaces);

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "processImage")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "processImage")]
#endif
        public static extern void processImage(IntPtr buffer);

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "releaseImageRenderer")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "releaseImageRenderer")]
#endif
        public static extern void releaseImageRenderer();

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "setRenderEnable")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "setRenderEnable")]
#endif
        public static extern bool setRenderEnable(bool enable);

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "setBeauty")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "setBeauty")]
#endif
        public static extern bool setBeauty(int type, int value);

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "setReshape")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "setReshape")]
#endif
        public static extern bool setReshape(int type, int value);

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "setFilter")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "setFilter")]
#endif
        public static extern bool setFilter(int type, String name, int value);

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "setARItem")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "setARItem")]
#endif
        public static extern bool setARItem(int type, String name);

#if DEBUG
        [DllImport("HTEffectD.dll", EntryPoint = "getVersion")]
#else
        [DllImport("HTEffect.dll", EntryPoint = "getVersion")]
#endif
        public static extern IntPtr getVersion();
        // === 引用HTEffectSDK C++动态库和方法 end ===

        // 初始化HTEffectSDK
        public static void initHTEffectSDK() {
            // TODO: Set your license and bundle path
            String licenseStr = "Your HTEffectSDK Lincese String";
            String bundlePath = "Your HTEffectBundle Path";
            int initStatus = authorizeSDK(licenseStr, bundlePath);
            Console.WriteLine("init status: " + initStatus);
            
            // 获取HTEffectSDK版本号
            IntPtr version = getVersion();
            string versionStr = Marshal.PtrToStringAnsi(version);
            Console.WriteLine("HTEffectSDK version: " + versionStr);
        }

        // === 创建纹理环境相关 start ===
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct PIXELFORMATDESCRIPTOR
        {
            public ushort nSize;
            public ushort nVersion;
            public uint dwFlags;
            public byte iPixelType;
            public byte cColorBits;
            public byte cRedBits;
            public byte cRedShift;
            public byte cGreenBits;
            public byte cGreenShift;
            public byte cBlueBits;
            public byte cBlueShift;
            public byte cAlphaBits;
            public byte cAlphaShift;
            public byte cAccumBits;
            public byte cAccumRedBits;
            public byte cAccumGreenBits;
            public byte cAccumBlueBits;
            public byte cAccumAlphaBits;
            public byte cDepthBits;
            public byte cStencilBits;
            public byte cAuxBuffers;
            public byte iLayerType;
            public byte bReserved;
            public uint dwLayerMask;
            public uint dwVisibleMask;
            public uint dwDamageMask;
        };

        [DllImport("user32.dll", ExactSpelling = false, EntryPoint = "GetDC", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        internal static extern IntPtr GetDC(IntPtr hwnd);

        [DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
        internal static extern IntPtr CreateWindowEx(int dwExStyle,
                                              string lpszClassName,
                                              string lpszWindowName,
                                              int style,
                                              int x, int y,
                                              int width, int height,
                                              IntPtr hwndParent,
                                              IntPtr hMenu,
                                              IntPtr hInst,
                                              [MarshalAs(UnmanagedType.AsAny)] object pvParam);

        [DllImport("gdi32.dll", ExactSpelling = false, EntryPoint = "ChoosePixelFormat", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        internal static extern int ChoosePixelFormat(IntPtr hdc, IntPtr ppfd);

        [DllImport("gdi32.dll", ExactSpelling = false, EntryPoint = "SetPixelFormat", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        internal static extern bool SetPixelFormat(IntPtr hdc, int format, IntPtr ppfd);

        [DllImport("opengl32.dll", ExactSpelling = false, EntryPoint = "wglCreateContext", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        internal static extern IntPtr wglCreateContext(IntPtr hdc);

        [DllImport("opengl32.dll", ExactSpelling = false, EntryPoint = "wglMakeCurrent", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        internal static extern bool wglMakeCurrent(IntPtr hdc, IntPtr hglrc);

        public static void InitOpenGL() {
            IntPtr hWnd = CreateWindowEx(0, "EDIT", "",  80, 0, 0, 1, 1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0);//图片框的窗口句柄
            IntPtr hdc = GetDC(hWnd);//取得设备上下文

            PIXELFORMATDESCRIPTOR pfd;//定义一个像素格式描述器

            //设置像素格式
            pfd.nSize = 40;
            pfd.nVersion = 1;
            pfd.dwFlags = 0x00000020 | 0x00000001 | 0x00000004;
            pfd.iPixelType = 0;
            pfd.cColorBits = 32;
            pfd.cRedBits = 0;
            pfd.cRedShift = 0;
            pfd.cGreenBits = 0;
            pfd.cGreenShift = 0;
            pfd.cBlueBits = 0;
            pfd.cBlueShift = 0;
            pfd.cAlphaBits = 0;
            pfd.cAlphaShift = 8;
            pfd.cAccumBits = 0;
            pfd.cAccumRedBits = 0;
            pfd.cAccumGreenBits = 0;
            pfd.cAccumBlueBits = 0;
            pfd.cAccumAlphaBits = 0;
            pfd.cDepthBits = 0;
            pfd.cStencilBits = 24;
            pfd.cAuxBuffers = 8;
            pfd.iLayerType = 0;
            pfd.bReserved = 0;
            pfd.dwLayerMask = 0;
            pfd.dwVisibleMask = 0;
            pfd.dwDamageMask = 0;

            int pixelFormat;

            unsafe
            {
                PIXELFORMATDESCRIPTOR* ppfd = &pfd;

                pixelFormat = ChoosePixelFormat(hdc, (IntPtr)ppfd);//选择像素格式

                SetPixelFormat(hdc, pixelFormat, (IntPtr)ppfd);//设置像素格式

                IntPtr hglrc;
                hglrc = wglCreateContext(hdc);//建立OpenGL渲染上下文

                wglMakeCurrent(hdc, hglrc);//激活当前渲染上下文
            }
        }
        // === 创建纹理环境相关 end ===


        static void Main(string[] args)
        {
            // 初始化HTEffectSDK
            initHTEffectSDK();
            // 初始化OpenGL纹理环境
            InitOpenGL();
            VideoCapture capture = new VideoCapture(0);
            bool isMirror = true;
            // 是否成功初始化渲染器
            bool isInitHTEffect = false;
            while (capture.IsOpened())
            {
                Mat frame = new Mat();
                capture.Read(frame);

                if (frame.Empty()) {
                    break;
                }
                Cv2.CvtColor(frame, frame, ColorConversionCodes.BGR2BGRA);
                
                // 初始化渲染器
                if (!isInitHTEffect) {
                    isInitHTEffect = initBufferRenderer(3, frame.Cols, frame.Rows, 0, false, 5);
                }

                // 渲染功能方法，可参考接口文件
                setBeauty(0, 80);
                setBeauty(1, 80);
                setReshape(10, 70);
                setReshape(20, 70);
                setFilter(0, "ziran3", 100);
                setARItem(0, "ht_sticker_effect_rabbit_bowknot");

                // 渲染方法
                processBuffer(frame.Data);

                if (isMirror)
                {
                    Cv2.Flip(frame, frame, FlipMode.Y);
                }
                Cv2.ImShow("OpenCVSharp Camere", frame);
                Cv2.WaitKey(30);
            }

            // 渲染图像示例
/*            Mat image = Cv2.ImRead("../../../resource/image_test_02.jpeg", ImreadModes.Color);

            if (image.Empty())
            {
                Console.WriteLine("Could not load image...");
                return;
            }

            // 初始化渲染器
            if (!isInitHTEffect)
            {
                isInitHTEffect = initImageRenderer(2, image.Cols, image.Rows, 0, false, 5);
            }

            // 渲染功能方法，可参考接口文件
            setBeauty(0, 80);
            setBeauty(1, 80);
            setReshape(10, 70);
            setReshape(20, 70);
            setFilter(0, "ziran3", 100);
            setARItem(0, "ht_sticker_effect_rabbit_bowknot");

            // 渲染方法
            processImage(image.Data);

            // 显示原始图像
            Window.ShowImages(image);

            // 等待用户按键，然后关闭所有窗口
            Cv2.WaitKey(0);
            Cv2.DestroyAllWindows();*/
        }
    }
}
